package com.example.gateway.filter;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.UUID;

/**
 * 自定义过滤器工厂（局部过滤器）
 * 它是一个 局部过滤器（不是全局的 GlobalFilter）；
 * 它是一个 过滤器工厂（用于构建具体 GatewayFilter）；
 * 能在 HTTP 响应返回前，动态地向响应头添加一个一次性 Token：
 * 支持类型：UUID、JWT（示例写死的）；
 * Header 名称由配置参数 name 指定；
 * Header 值的生成策略由配置参数 value 决定（uuid/jwt）。
 */

/**
 * 继承了 Spring Cloud Gateway 的快捷工厂类 AbstractNameValueGatewayFilterFactory；
 * 该类自动提供一个配置对象 NameValueConfig，包含两个字段：
 * name（Header 名称）
 * value（Header 内容或控制添加的 Token 类型）
 */
@Component
public class OnceTokenGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {

    /**
     * 这是工厂方法，用于根据传入配置创建实际的 GatewayFilter 对象。
     */
    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                /**
                 * 定义响应拦截逻辑
                 * 每次响应之前，添加一个一次性令牌，支持uuid，jwt等各种格式
                 * <p></p>
                 * chain.filter(exchange) 表示将请求继续传递；
                 * .then(...) 是 Reactor 的 post 处理钩子，用于响应返回前的逻辑；
                 * 最终通过 exchange.getResponse().getHeaders().add(...) 添加响应头。
                 */
                return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                    ServerHttpResponse response = exchange.getResponse();
                    HttpHeaders headers = response.getHeaders();
                    String value = config.getValue();
                    if ("uuid".equalsIgnoreCase(value)) {
                        value = UUID.randomUUID().toString();
                    }
                    if ("jwt".equalsIgnoreCase(value)) {
                        value = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9." +
                                "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ." +
                                "SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
                    }
                    headers.add(config.getName(), value);
                }));
            }
        };
    }

}
